// Extend.js (http://code.google.com/p/extendjs/)
// Copyright 2010 Shumpei Shiraishi All rights reserved.
// Licensed under the MIT license.

(function(_global) {
    // ===== extend built-in object
    // X.Object.extend(name, method, generateX, override)
    // X.Object.extend(proto, generateX, override)

    //object
    X.extend("Object", function(value) {
	// X.Object is fallback type when other type is not particuler.
	// So we always return false.
	return false;
    });
    X.Object.extend({
	isExtended: function() {
	    return true;
	},
	isUndefined: function() {
	    return false;
	},
	isNull: function() {
	    return false;
	},
	isString: function() {
	    return false;
	},
	isNumber: function() {
	    return false;
	},
	isBoolean: function() {
	    return false;
	},
	isFunction: function() {
	    return false;
	},
	isArray: function() {
	    return false;
	},
	isDate: function() {
	    return false;
	},
	isRegExp: function() {
	    return false;
	},
	isEmpty: function() {
	    for (var key in this.__val) {
		return false;
	    }
	    return true;
	},
	extend: function(dest) {
	    return X.util.extend(dest, this.__val);
	},
	val: function() {
	    return this.__val;
	},
	keys: function() {
	    var val = this.__val;
	    var results = [];
	    for (var property in val)
		results.push(property);
	    return results;
	},
	contains: function(val) {
	    return this.containsValue(val);
	},
	containsValue: function(val) {
	    var obj = this.__val;
	    for (var key in obj) {
		if (obj[key] == val) {
		    return true;
		}
	    }
	    return false;
	},
	containsKey: function(key) {
	    return key in this.__val;
	},
	values: function() {
	    var val = this.__val;
	    var results = [];
	    for (var property in val)
		results.push(val[property]);
	    return results;
	},
	transpose: function() {
	    var obj = this.__val;
	    var transposed = {};
	    for (var key in obj) {
		transposed[obj[key]] = key;
	    }
	    return transposed;
	},
	clear: function() {
	    // Some versions of IE has problems if we delete keys from the beginning
	    var keys = this.keys();
	    for (var i = keys.length - 1; i >= 0; i--) {
		this.remove(keys[i]);
	    }
	},
	remove: function(key) {
	    var obj = this.__val;
	    var rv;
	    if ((rv = key in obj)) {
		delete obj[key];
	    }
	    return rv;
	},
	clone: function() {
	    return this.extend({});
	},
	join: function(nameValDelim, tokenDelim) {
	    if (nameValDelim === undefined) {
		nameValDelim = "=";
	    }
	    if (tokenDelim === undefined) {
		tokenDelim = ",";
	    }
	    var tokens = [];
	    function buildTokens(name, value) {
		if (value instanceof Array) {
		    X(value).each(function(val, index) {
			buildTokens(name, val);
		    });
		} else {
		    name = String(name), value = String(value);
		    tokens.push(name + nameValDelim + value);
		}
	    }
	    this.each(function(value, name) {
		buildTokens(name, value);
	    });
	    return tokens.join(tokenDelim);
	},
	each: function(f, opt_obj) {
	    this.forEach(f, opt_obj);
	},
	forEach: function(f, opt_obj) {
	    var obj = this.__val;
	    for (var key in obj) {
		f.call(opt_obj, obj[key], key, obj);
	    }
	},
	filter: function(f, opt_obj) {
	    var res = {};
	    this.forEach(function(value, key) {
		if (f.call(opt_obj, obj[key], key, obj)) {
		    res[key] = obj[key];
		}
	    });
	    return res;
	},
	map: function(f, opt_obj) {
	    var obj = this.__val;
	    var res = {};
	    for (var key in obj) {
		res[key] = f.call(opt_obj, obj[key], key, obj);
	    }
	    return res;
	},
	some: function(f, opt_obj) {
	    var obj = this.__val;
	    for (var key in obj) {
		if (f.call(opt_obj, obj[key], key, obj)) {
		    return true;
		}
	    }
	    return false;
	},
	every: function(f, opt_obj) {
	    var obj = this.__val;
	    for (var key in obj) {
		if (!f.call(opt_obj, obj[key], key, obj)) {
		    return false;
		}
	    }
	    return true;
	},
	findKey: function(f, opt_this) {
	    var obj = this.__val;
	    for (var key in obj) {
		if (f.call(opt_this, obj[key], key, obj)) {
		    return key;
		}
	    }
	    return undefined;
	},
	findValue: function(f, opt_this) {
	    var key = this.findKey(f, opt_this);
	    return key && this.__val[key];
	}
    });
    var NATIVE_METHODS_OBJECT = [
	"toString", "toLocaleString", "valueOf",
	"hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable"
    ];
    X.Object.mixin(Object.prototype, NATIVE_METHODS_OBJECT);
})(this);
